import * as THREE from "three";

export class Model {
    // instancemesh 10000000 scene 10000
    // mesh 400000 scene 3000
    totalMeshCount = 440000; //Math.pow(10, 5);
    boxGeometry: THREE.BoxGeometry;
    material: THREE.Material;
    scenes: THREE.Scene[] = [];
    totalSceneCount = 3000;
    boundingBox!: THREE.Mesh[];
    boundingBoxScene!: THREE.Scene;
    private meshes: THREE.Mesh[] = [];
    private cellSize = 4;
    constructor() {
        this.boxGeometry = new THREE.BoxBufferGeometry(this.cellSize, this.cellSize, this.cellSize);
        this.material = new THREE.MeshNormalMaterial();

        this.scenes = this.generateMeshScene();
        // this.scenes = this.generateInstanceMeshScene();

        this.boundingBoxScene = this.generateBoundingBoxScene();
    }
    private generateInstanceMeshScene() {
        this.scenes = [];
        const count = this.totalMeshCount;
        const transform = new THREE.Object3D();
        const zStart = -400;
        const zEnd = 400;
        const zSize = zEnd - zStart;
        const layerHeight = zSize / this.totalSceneCount;
        // 80层
        for (let z = zStart; z < zEnd; z += layerHeight) {
            const tempScene = new THREE.Scene();
            const countPerLayer = count / this.totalSceneCount;
            let i = 0;
            const instancedMeshLayer = new THREE.InstancedMesh(this.boxGeometry, this.material, count / (zSize / layerHeight));
            // 每层随机布置
            for (let index = 0; index < countPerLayer; index++) {
                transform.position.set(Math.random() * zSize - zSize / 2, Math.random() * zSize - zSize / 2, z);
                transform.updateMatrix();
                instancedMeshLayer.setMatrixAt(i++, transform.matrix);
            }
            tempScene.add(instancedMeshLayer);
            this.scenes.push(tempScene);
        }
        return this.scenes;
    }
    private generateMeshScene() {
        this.meshes = [];
        this.scenes = [];
        // [-400,400]的大正方体空间中 10边长的小正方体
        for (let index = 0; index < this.totalMeshCount; index++) {
            const mesh = new THREE.Mesh(this.boxGeometry, this.material);
            mesh.position.copy(new THREE.Vector3(Math.random() * 800 - 400, Math.random() * 800 - 400, Math.random() * 800 - 400));
            this.meshes.push(mesh);
        }
        this.meshes.sort((a: THREE.Mesh, b: THREE.Mesh) => {
            return (a.position.z - b.position.z) * 1
                + (a.position.x - b.position.x) * 100
                + (a.position.y - b.position.y) * 10000;
        });

        // 形成批次
        for (let i = 0; i < this.totalSceneCount; i++) {
            const tempScene = new THREE.Scene();
            const countMeshPerScene = this.totalMeshCount / this.totalSceneCount;
            for (let j = 0; j < countMeshPerScene; j++) {
                tempScene.add(this.meshes.at(i * countMeshPerScene + j)!);
            }
            this.scenes.push(tempScene);
        }
        return this.scenes;
    }
    private generateBoundingBoxScene() {
        this.material = new THREE.MeshPhongMaterial({ color: 0xffffff });
        const mesh0 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh0.position.copy(new THREE.Vector3(-400, -400, -400));
        const mesh1 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh1.position.copy(new THREE.Vector3(-400, -400, 400));
        const mesh2 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh2.position.copy(new THREE.Vector3(-400, 400, -400));
        const mesh3 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh3.position.copy(new THREE.Vector3(-400, 400, 400));
        const mesh4 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh4.position.copy(new THREE.Vector3(400, -400, -400));
        const mesh5 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh5.position.copy(new THREE.Vector3(400, -400, 400));
        const mesh6 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh6.position.copy(new THREE.Vector3(400, 400, -400));
        const mesh7 = new THREE.Mesh(this.boxGeometry, this.material);
        mesh7.position.copy(new THREE.Vector3(400, 400, 400));
        this.boundingBox = [mesh0, mesh1, mesh2, mesh3, mesh4, mesh5, mesh6, mesh7];
        this.boundingBoxScene = new THREE.Scene();
        this.boundingBoxScene.add(...this.boundingBox);
        this.boundingBoxScene.add(new THREE.AmbientLight(new THREE.Color(0xffffff), 1));
        return this.boundingBoxScene;
    }
    getScenes(): THREE.Scene[]{
        return this.scenes;
    }


}